# 复制自实验六第一题
from typing import Iterable


class Matrix:
    def __init__(self, row: int, col: int, values: Iterable[float] = None):
        def generate_values():
            for value in values:
                yield value
            while True:
                yield 0
        if col <= 0 or row <= 0:
            raise ValueError()
        generated = iter(generate_values())
        self._storage: list[list[float]] = \
            [[next(generated) for _ in range(col)] for _ in range(row)]

    # @staticmethod
    # def create_two_dimension(col: int, row: int, values: Iterable[Iterable[float]]):
    #    def generate_values():
    #        for r in values:
    #            for v in r:
    #                yield v
    #    return Matrix(col, row, generate_values())

    @property
    def row_count(self):
        return len(self._storage)

    @property
    def col_count(self):
        return len(self._storage[0])

    def set_value(self, i: int, j: int, value: float):
        self._storage[i][j] = value

    def get_value(self, i: int, j: int):
        return self._storage[i][j]

    def get_row(self, i: int):
        for value in self._storage[i]:
            yield value

    def get_rows(self):
        for i in range(self.row_count):
            yield self.get_row(i)

    def get_col(self, j: int):
        for i in range(self.row_count):
            yield self._storage[i][j]

    def get_cols(self):
        for j in range(self.col_count):
            yield self.get_col(j)

    def format(self, item_format: str = ".2f", item_sep: str = " ", line_sep: str = "\n"):
        def generate_strs(lst: list[float]):
            for v in lst:
                yield v.__format__(item_format)

        def generate_lines():
            for r in self._storage:
                yield item_sep.join(generate_strs(r))

        return line_sep.join(generate_lines())

    def __str__(self):
        return str(self._storage)

    def transposed(self):
        t = [self._storage[i][j] for j in range(self.col_count) for i in range(self.row_count)]
        return Matrix(row=self.col_count, col=self.row_count, values=t)

    @staticmethod
    def product(left: 'Matrix', right: 'Matrix'):
        if left.col_count != right.row_count:
            return None

        def inner_product(vector1: Iterable[float], vector2: Iterable[float]):
            result = 0
            for v1, v2 in zip(vector1, vector2):
                result += v1 * v2
            return result

        def get_rows_list(m: 'Matrix'):
            for r in m.get_rows():
                yield list(r)

        t = [inner_product(row, col) for row in get_rows_list(left) for col in right.get_cols()]
        return Matrix(left.row_count, right.col_count, t)
